using System.Security.Principal;

namespace SecurePO
{
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices;
    using System.Text.RegularExpressions;

    public static class ActiveDirectoryHelper
    {
        private static readonly string nameFormat = "(cn={0})";
        private static readonly string fullNameKey = "name";
        private static readonly string objectSidKey = "objectSID";
        private static readonly Regex nameRegex = new Regex("CN=([^,]*),", RegexOptions.Compiled);

        public static string GetUserNameBySid(string sid)
        {
            const string SidSearchFormat = "LDAP://<SID={0}>";
            DirectoryEntry userEntry = new DirectoryEntry(string.Format(SidSearchFormat, sid));
            try
            {
                return userEntry.Properties["Name"].Value.ToString();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Write(e.Message);
                WindowsIdentity i = System.Security.Principal.WindowsIdentity.GetCurrent();
                return i.Name;
            }
        }

        public static String GetUserName(String loginName)
        {
            string retval = String.Empty;
            loginName = loginName.Contains("\\") ? loginName.Split(new[] { '\\' })[1] : loginName;
            DirectorySearcher searcher = new DirectorySearcher { Filter = string.Format(("(anr={0})"), loginName) };
            try
            {
                SearchResult result = searcher.FindOne();
                if (result != null)
                {
                    retval = result.GetDirectoryEntry().Properties["Name"].Value.ToString();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Write(e.Message);
                WindowsIdentity i = System.Security.Principal.WindowsIdentity.GetCurrent();
                retval = Environment.UserName;
            }
            return retval;
        }

        public static String[] GetUserGroups(String userName)
        {
            const string MEMBEROF = "memberOf";
            DirectorySearcher search = new DirectorySearcher { Filter = String.Format(nameFormat, userName) };
            search.PropertiesToLoad.Add(MEMBEROF);
            List<String> result = new List<string>();
            SearchResult searchResult = search.FindOne();
            if (searchResult != null)
            {
                ResultPropertyValueCollection items = searchResult.Properties[MEMBEROF];
                for (int i = 0; i < items.Count; i++)
                {
                    if (items[i] != null)
                    {
                        result.Add(nameRegex.Match(((string)items[i])).Groups[1].Value);
                    }
                }
            }

            return result.ToArray();
        }

        public static String[] GetGroupUsers(String groupName)
        {
            List<String> result = new List<string>();
            const string MEMBER = "member";
            DirectorySearcher search = new DirectorySearcher { Filter = String.Format(nameFormat, groupName) };
            search.PropertiesToLoad.Add(MEMBER);
            SearchResult searchResult = search.FindOne();
            if (searchResult != null)
            {
                ResultPropertyValueCollection items = searchResult.Properties[MEMBER];
                for (Int32 i = 0; i < items.Count; i++)
                {
                    if (items[i] != null)
                    {
                        result.Add(nameRegex.Match(((string)items[i])).Groups[1].Value);
                    }
                }
            }

            return result.ToArray();
        }

        public static String[] GetGroups()
        {
            List<String> results = new List<string>();
            const string QUERY = "(&(objectCategory=group))";
            DirectorySearcher search = new DirectorySearcher { Filter = QUERY };
            SearchResultCollection result = search.FindAll();
            if (result.Count > 0)
            {
                for (int i = 0; i < result.Count; i++)
                {
                    if (null != result[i].Properties[fullNameKey] && result[i].Properties[fullNameKey].Count == 1)
                    {
                        results.Add(result[i].Properties[fullNameKey][0] as String);
                    }
                }
            }

            return results.ToArray();
        }

        public static Dictionary<string,string> GetUsers()
        {
            Dictionary<string, string> results = new Dictionary<string, string>();
            const string QUERY = "(&(objectCategory=user))";
            DirectorySearcher srch = new DirectorySearcher { Filter = QUERY };
            try
            {
                SearchResultCollection result = srch.FindAll();
                if (result.Count > 0)
                {
                    for (int i = 0; i < result.Count; i++)
                    {
                        if (null != result[i].Properties[objectSidKey] && result[i].Properties[objectSidKey].Count == 1)
                        {
                            Byte[] sidArray = ((Byte[])result[i].Properties[objectSidKey][0]);
                            SecurityIdentifier sid = new SecurityIdentifier(sidArray, 0);
                            results.Add(sid.Value, result[i].Properties[fullNameKey][0] as String);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Write(e.Message);
                WindowsIdentity i = System.Security.Principal.WindowsIdentity.GetCurrent();
                results.Add(i.User.Value, i.Name);
            }
            return results;
        }
    }
}